#include "stdafx.h"
#include <windows.h> 
#include <strsafe.h>
#include <locale>
#include "resource.h"
#include "MFCTiffMergerDlg.h"
#include "SplitPDF.h"

#include "TiffLogger.h"

#define BUFSIZE 4096 
 
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

void WriteToPipe(void); 
void ReadFromPipe(void); 
void ErrorExit(PTSTR); 

void Init(void) {
	SECURITY_ATTRIBUTES saAttr; 
	// Set the bInheritHandle flag so pipe handles are inherited. 
 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	// Create a pipe for the child process's STDOUT. 
	if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) 
		ErrorExit(TEXT("StdoutRd CreatePipe")); 

	// Ensure the read handle to the pipe for STDOUT is not inherited.
	if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
		ErrorExit(TEXT("Stdout SetHandleInformation")); 

	// Create a pipe for the child process's STDIN.  
	if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
		ErrorExit(TEXT("Stdin CreatePipe")); 

	// Ensure the write handle to the pipe for STDIN is not inherited.  
	if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
		ErrorExit(TEXT("Stdin SetHandleInformation")); 
} 
 
void CreateChildProcess(const CString &processNameWithParameters)
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
	TCHAR szCmdline[]=TEXT("child");
	PROCESS_INFORMATION piProcInfo; 
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE; 
 
	// Set up members of the PROCESS_INFORMATION structure. 
 
	ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
 
	// Set up members of the STARTUPINFO structure. 
	// This structure specifies the STDIN and STDOUT handles for redirection.
 
	ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
	siStartInfo.cb = sizeof(STARTUPINFO); 
	siStartInfo.hStdError = g_hChildStd_OUT_Wr;
	siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
	siStartInfo.hStdInput = g_hChildStd_IN_Rd;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
 
	// Create the child process.     
	bSuccess = CreateProcess(NULL, 
      (LPWSTR)(LPCWSTR)processNameWithParameters,     // command line 
      NULL,          // process security attributes 
      NULL,          // primary thread security attributes 
      TRUE,          // handles are inherited 
      0,             // creation flags 
      NULL,          // use parent's environment 
      NULL,          // use parent's current directory 
      &siStartInfo,  // STARTUPINFO pointer 
      &piProcInfo);  // receives PROCESS_INFORMATION 
   
	// If an error occurs, exit the application. 
	if ( ! bSuccess ) 
		ErrorExit(TEXT("CreateProcess"));
	else 
	{
		// Close handles to the child process and its primary thread.
		// Some applications might keep these handles to monitor the status
		// of the child process, for example. 

		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);
	}
}
 
// Deprecated
void WriteToPipe(void) 

// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data. 
{ 
	DWORD dwRead, dwWritten; 
	CHAR chBuf[BUFSIZE];
	BOOL bSuccess = FALSE;
 
	for (;;) 
	{ 
		/*bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL);
		if ( ! bSuccess || dwRead == 0 ) break; */
      
		bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
		if ( ! bSuccess ) break; 
	} 
 
	// Close the pipe handle so the child process stops reading. 
 
	if ( ! CloseHandle(g_hChildStd_IN_Wr) ) 
		ErrorExit(TEXT("StdInWr CloseHandle")); 
} 

CString mbstoCString(const char* src)
{
	_locale_t locale;
	locale = _create_locale(LC_CTYPE, "chs");
	size_t numberOfwchars;	
	_mbstowcs_s_l(&numberOfwchars, NULL, 0, src, 0, locale);
	wchar_t *wbuf = new wchar_t[numberOfwchars];
	_mbstowcs_s_l(&numberOfwchars, wbuf, numberOfwchars, src, numberOfwchars, locale);	
	CString result(wbuf);
	_free_locale(locale);
	delete[] wbuf;

	return result;
}

BOOL ReadFileWithCarriageReturn(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) 
{
	CHAR chBuf[BUFSIZE] = {0};
	DWORD dwRead;
	BOOL bSuccess = FALSE;
	int numberOfCarriages = 0;
	for (;;) {
		bSuccess = ReadFile(hFile, chBuf, BUFSIZE, &dwRead, NULL);
		if (!bSuccess || dwRead <= 0)
			break;

		CString result = mbstoCString(chBuf);
		

	}
}

CString remained(L"");


void updateList(const CString &item) 
{
	CMFCTiffMergerDlg* dlg = (CMFCTiffMergerDlg*)AfxGetApp()->GetMainWnd();
	CListBox* splittedFileNames = (CListBox*)dlg->m_page2.GetDlgItem(IDC_SPLITTED_FILEPATH_LIST);

	splittedFileNames->AddString(item);
	// Set the focus the last added item
	splittedFileNames->SetTopIndex(splittedFileNames->GetCount() - 1);
	splittedFileNames->UpdateWindow();
	dlg->m_page2.PostMessageW(WM_UPDATE_USER1, 0, 0);		
}

void parserAndShowOutput(const char *chBuf) 
{
	CString result = remained + L"\r\n" + mbstoCString(chBuf);
	int iStart = 0;
	CString pre(L""), token(L"");
	while (iStart != -1) {
		if (pre == L"") {
			pre = token = result.Tokenize(L"\r\n", iStart);
		} else {
			pre = token;
			token = result.Tokenize(L"\r\n", iStart);
		}

		if (pre != L"" && pre != token && iStart != -1) {
			updateList(pre);
		} else if (iStart == -1){
			remained = pre;
		}
	}
}


 
void ReadFromPipe(void) 

// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT. 
// Stop when there is no more data. 
{ 
	DWORD dwRead; 
	CHAR chBuf[BUFSIZE] = {0}; 
	BOOL bSuccess = FALSE;	
	for (;;) 
	{ 
		bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
		if( ! bSuccess || dwRead <= 2 ) break; 
		 // Update the list box
		parserAndShowOutput(chBuf);

		memset(chBuf, 0, BUFSIZE);
	} 

	if (remained != L"") {
		updateList(remained);
	}
} 
 
void ErrorExit(PTSTR lpszFunction) 

// Format a readable error message, display a message box, 
// and exit from the application.
{
	LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(1);
}

void SplitPDF(const CString &pdffilePath)
{
	
	Init();
	CString doubleQuote(L"\"");
	TCHAR cmdLines[MAX_PATH] = {L"MyPDFSplitter.exe \""};
	CString backslash = pdffilePath;
	backslash.Replace(L"\\", L"/");
	_tcscat_s(cmdLines, MAX_PATH, backslash);
	_tcscat_s(cmdLines, MAX_PATH, doubleQuote);

	CreateChildProcess(cmdLines);
	CloseHandle(g_hChildStd_OUT_Wr);
	ReadFromPipe();
	CloseHandle(g_hChildStd_OUT_Rd);
}